//TESTING SVN
package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.sql.Time;


import ClientGui.Controller;
import clientData.ForumData;
import clientData.ForumDataInt;
import clientData.MemberData;

import clientData.MemberDataInt;
import clientData.PostData;
import clientData.PostDataInt;
import clientData.TopicData;
import clientData.TopicDataInt;
import server.ForumHandlerInt;
import sun.awt.image.ImageWatched.Link;

import exception.ForumNotFoundException;
import java.util.Date;

import java.util.Iterator;
import java.util.LinkedList;


//import domainModel.NotificationMsg;
import java.util.Vector;


import java.util.logging.Logger;




import server.NotificationMsg;
import exception.ElementNotFoundException;
import exception.FriendNotFoundException;
import exception.NoPermissionException;
import exception.NotLoggedInException;
import exception.NotRegisteredException;
import exception.NotUserPostException;
import exception.PostNotExistException;
import exception.TopicNotFoundException;
import exception.UserNameExistException;
import java.sql.SQLException;

//79.179.111.3
/**
 * The Class ForumClient.
 */
public class ForumClient {
   String serverDomain = "localhost";
    ForumHandlerInt forum;
    public Vector <ForumDataInt> forums = new Vector <ForumDataInt>() ;
    public Vector <TopicDataInt> topics = new Vector <TopicDataInt>() ;
    public Vector <PostDataInt>  posts = new Vector <PostDataInt>();
    public Vector<MemberDataInt> friends;
    String password;
    String user;
    public boolean logged;
    boolean admin;
    String cmd;
    String options;
    int forumId;
    int topicId;
    int postId;
    public String returnValue;
    Logger logger;
    private ForumDataInt currentForum;
    private TopicDataInt currentTopic;
    private PostDataInt currentPost;
    
    public ForumDataInt getCurrentForum() {
        return currentForum;
    }

    public PostDataInt getCurrentPost() {
        return currentPost;
    }

    public TopicDataInt getCurrentTopic() {
        return currentTopic;
    }

    public ForumClient() {
        try {
        	logger = Logger.getLogger("clientLog.txt");
            forum = (ForumHandlerInt)Naming.lookup("rmi://"+serverDomain+"/ForumService");
            password = null;
            user = null;
            logged = false;
            admin = false;
            cmd = null;
            forumId = -1;
            topicId = -1;
            postId = -1;
            forums = new Vector<ForumDataInt>();
            topics = new Vector<TopicDataInt>();
            posts = new Vector<PostDataInt>();
            friends = new Vector<MemberDataInt>();
        }
        catch (MalformedURLException murle) {
            System.out.println("\nMalformedURLException: " + murle);
        }
        catch (RemoteException re) {
            System.out.println("\nRemoteException: " + re);
        }
        catch (NotBoundException nbe) {
            System.out.println("\nNotBoundException: " + nbe);
        }
        catch (java.lang.ArithmeticException ae) {
            System.out.println("\njava.lang.ArithmeticException: " + ae);
        }
        catch (Exception e) {
           System.out.println("\nbig problem: " + e.getMessage());e.printStackTrace();
        }
    }

    /**
     * The main method.
     *
     * @param args the arguments
     */
    public static void main(String[] args) {
    	ForumClient client = new ForumClient();
    	Controller.initGui(client);
    	while(true){}
    }
    
    InputStreamReader converter = new InputStreamReader(System.in);
    BufferedReader in = new BufferedReader(converter);
	private Thread listener;
	private Vector<MemberDataInt> searched_friends;
       
       public void choosePost(PostDataInt _post) {
    	   if(_post.getId() < 0){
    		   returnValue = "An error has occured trying to enter post";
    		   return;
    	   }
    	   postId = _post.getId();
           currentPost = _post;
       }

	public void chooseTopic(TopicDataInt topic) {
    	   if(logged & forumId>=0){
	    		topicId = topic.getId();
                        currentTopic = topic;
	       		postId = -1;
	       	   	showPosts();
    	   }
   		   else if (!logged)
   		   logger.warning("You must login");
   	   else logger.warning("You must choose a forum first...");
	}

	public void chooseForum(ForumDataInt forum) {
		if(logged & forums!=null && forums.size()>0){
			forumId = forum.getId();
                currentForum = forum;
       		topicId = -1;
       		postId = -1;
   	     	showTopics();
   	   } else if(!logged)
   		   logger.warning("You must login");
   	   else if(forums == null)
   		   logger.warning("can't get forums list");
   	   else logger.warning("You can create a new forum using the \"create-forum\" operation");
	}

	public boolean register(String userName, String _password, String id, String email, String firstName, String lastName){
		try {
			forum.register(userName, _password, Integer.valueOf(id).intValue(), email, firstName, lastName);
			return true;
		} catch (UserNameExistException e){
			returnValue = "User name allready exist, choose a different name!";
			logger.warning("user name: " + userName + " allready exists");
			return false;
			}
                catch (SQLException e7) {
                        returnValue = getSQLerror();
                        logger.warning(e7.getMessage());
                        return false;
                }
		catch (Exception e1){
			returnValue = "Register faliure";
			logger.warning(e1.getMessage());
			return false;
			}
	}
       
       
       public boolean login(String _userName , String _password) {
    	   try {
    		   if(forum.login(_userName , _password).equals("ADMIN"))
    			   	admin = true;
    		   	user = _userName;
    			password = _password;
    			logged = true;
    			startListener();
    			return true;
    	   	} catch (NotRegisteredException e){
    	   		returnValue = "User "+_userName+" is not registered";
    	   		return false;
    	   	} catch (SQLException e7) {
                        returnValue = getSQLerror();
                        logger.warning(e7.getMessage());
                        return false;
                } catch(Exception e1){
    	   		returnValue = "Login failed";
    	   		logger.warning(e1.getMessage());
    	   		e1.printStackTrace();
    	   		return false;
                }
       }
//    	   else System.out.println("You're already logged in. If you want to switch users, please logout first");
       
       private void startListener() {
		listener = new Thread(new Runnable() {
						@Override
						public void run() {
							LinkedList<NotificationMsg> notification;
							while(true){
								try {
									notification = forum.getNotificationMsgs(user);
									if(notification != null){
										notificationHandler(notification);
									}
									else{
										logger.warning("The listener was wamkenup for no good reason");
									}
								} catch (RemoteException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (NotLoggedInException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						}

					});
		listener.start();
	}
       private void notificationHandler( LinkedList<NotificationMsg> notification) {
			Iterator<NotificationMsg> msgs = notification.iterator();
			NotificationMsg msg;
			while(msgs.hasNext()){
				msg = msgs.next();
				
				if (msg.getUserName().equals(user))
					continue;
                                Controller.addMsg(msg);
				switch (msg.getType()){
				case 0:
					friendAddedPost(msg);
                                            Controller.addMsg(msg);
					break;
				case 1:
					myTopicsNotification(msg);
					break;
				case 2:
					topicRefresh(msg);
					break;
                                    case 3:
                                            friendUpdatedPost(msg);
                                            Controller.addMsg(msg);
                                            break;
                                    case 4:
                                            postUpdatedInTopic(msg);
                                            topicRefresh(msg);
                                            break;
                                    case 5:
                                            postUpdated(msg);
                                            Controller.addMsg(msg);
                                            break;
                                    case 6:
                                        postDeleted(msg);
                                        break;
                                    case 7:
                                        postDeletedInTopic(msg);
                                        topicRefresh(msg);
                                        break;
                                    case 8:
                                        friendDeletedPost(msg);
                                        topicRefresh(msg);
                                        break;
				}
			}
       }
			
       private void postUpdatedInTopic(NotificationMsg msg){
           showPosts();
           Controller.showPosts();
       }

       private void friendDeletedPost(NotificationMsg msg){
           String str =
                   "Your friend - "+msg.getUserName()+" has updated the following post:\n"+
                        msg.getPost().getTitle()+"\n"+msg.getPost().getContent() + " - in the forum: "+
                        msg.getForum().getName()+" under the topic: "+
                        msg.getTopic().getTitle() + " !";
        //        System.out.println(str);
                Controller.notifyUser(str);
       }

       private void postDeletedInTopic(NotificationMsg msg){
           showPosts();
           Controller.showPosts();
       }

       private void postDeleted(NotificationMsg msg) {
           String str =
                   "Post '"+
                        msg.getPost().getTitle()+"' was removed from topic: "+ msg.getTopic().getTitle() + "\n"
                        +" in forum '"+  msg.getForum().getName() + "' !";
           Controller.notifyUser(str);
       }

	private void topicRefresh(NotificationMsg msg) {
                showPosts();
                Controller.showPosts();
	}

        private void postUpdated(NotificationMsg msg) {
		String str =
                        "User " + msg.getUserName()+" has updated the following post:\n"+
                        msg.getPost().getTitle()+"\n"+msg.getPost().getContent() + " - in the forum: "+
                        msg.getForum().getName()+" under the topic: "+
                        msg.getTopic().getTitle();
         //       System.out.println(str);
                Controller.notifyUser(str);
	}

	private void myTopicsNotification(NotificationMsg msg) {
		String str = 
                        "A post was added to the topic "+msg.getTopic().getTitle()+
                        " that you created in the forum "+msg.getForum().getName()+
                        "\nThe post title is: "+msg.getPost().getTitle();
         //       System.out.println(str);
                Controller.notifyUser(str);
	}

	private void friendAddedPost(NotificationMsg msg) {
		String str =
                        "Your friend - "+msg.getUserName()+" has added in the forum: "+
                        msg.getForum().getName()+" under the topic: "+
                        msg.getTopic().getTitle()+" the following post:\n"+
                        msg.getPost().getTitle()+"\n"+msg.getPost().getContent();
        //        System.out.println(str);
                Controller.notifyUser(str);
	}

        private void friendUpdatedPost(NotificationMsg msg) {
		String str =
                        "Your friend - "+msg.getUserName()+" has updated the following post:\n"+
                        msg.getPost().getTitle()+"\n"+msg.getPost().getContent() + " - in the forum: "+
                        msg.getForum().getName()+" under the topic: "+
                        msg.getTopic().getTitle();
        //        System.out.println(str);
                Controller.notifyUser(str);
	}

	public boolean logout() {
    	   try {
    		   forum.logout(user,password);
    		   logged = false;
    		   admin = false;
    		   forumId = -1;
    		   topicId = -1;
    		   postId = -1;
    		   return true;
    	   } catch(Exception e){
    		   returnValue = "Logout failed";
    		   logger.warning(e.getMessage());
    		   listener.interrupt();
    		   return false;
    		   }
       }
       
       		public boolean searchForFriend(String prefix) {
    				try {
    					searched_friends = listToVector(forum.lookForForumUsers(user, password, prefix));
    					return true;
	    		   	} catch(ElementNotFoundException e){
	    		   		returnValue = "No user name starts with "+ prefix;
	    		   		return false;
	    		   	} catch(NotLoggedInException e){
	    		   		logged = false;
	    		   		returnValue = "Time out, you must login again";
	    		   		return false;
	    		   	} catch (SQLException e7) {
                                        returnValue = getSQLerror();
                                        logger.warning(e7.getMessage());
                                        return false;
                                } catch (Exception e1) {
	    		   		logger.warning(e1.getMessage());
	    		   		returnValue = "System faliure";
	    		   		return false;
	    		   	}
       		}
       
                public Vector<MemberDataInt> getSearchedFriends(){
                    return this.searched_friends;
                }
       
    		public boolean editPost(String nTitle, String nContent) {
    			try {
    				forum.editPost(user, password, forumId, topicId, postId, nTitle, nContent);
	    		   	showPosts();
                                return true;
	    		   	} catch(NotUserPostException e){
	    		   		returnValue = "You didn't create this topic therefor you can't change it";
	    		   		return false;
	    		   	} catch (PostNotExistException e1){
	    		   		returnValue = "Wrong post id";
	    		   		return false;
	    		   	}catch (TopicNotFoundException e2){
	    		   		returnValue = "Wrong topic id";
	    		   		return false;
	    		   	}catch (ForumNotFoundException e3){
	    		   		returnValue = "Wrong forum id";
	    		   		return false;
	    		   	}catch(NotLoggedInException e4){
	    		   		logged = false;
	    		   		returnValue = "Time out, you must login again";
	    		   		return false;
		        	} catch (SQLException e7) {
                                        returnValue = getSQLerror();
                                        logger.warning(e7.getMessage());
                                        return false;
                                } catch (Exception e5) {
	    		   		logger.warning(e5.getMessage());
	    		   		returnValue = "System faliure";
	    		   		return false;
		        	}
		}


    		public boolean removePost() {
    			try{
                                forum.removePost(user, password, forumId, topicId, postId);
	    			showPosts();
	    			return true;
    			} catch (TopicNotFoundException e2){
    		   		returnValue = "Wrong topic id";
    		   		return false;
    		   	}catch (ForumNotFoundException e3){
    		   		returnValue = "Wrong forum id";
    		   		return false;
    		   	}catch(NotLoggedInException e4){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
	        	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e5) {
    		   		logger.warning(e5.getMessage());
    		   		returnValue = "System failure";
    		   		return false;
	        	}
                }

    		public boolean publishPost(String pTitle, String pContent) {
    			try{
	    			forum.publishPostInTopic(user, password, topicId, pTitle, forumId, pContent);
	    			showPosts();
	    			return true;
    			} catch (TopicNotFoundException e2){
    		   		returnValue = "Wrong topic id";
    		   		return false;
    		   	}catch (ForumNotFoundException e3){
    		   		returnValue = "Wrong forum id";
    		   		return false;
    		   	}catch(NotLoggedInException e4){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
	        	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e5) {
    		   		logger.warning(e5.getMessage());
    		   		returnValue = "System faliure";
    		   		return false;
	        	}
    }

    		public boolean showPosts() {
    			try {
	    		   		LinkedList<PostDataInt> _posts = forum.getPostList(user, password,topicId, forumId);
	    		   		posts = listToVector(_posts);
	    		   		return true;
	    		}catch(ElementNotFoundException e){
    		   		returnValue = "Wrong topic id";
    		   		return false;
    		   	} catch(NotLoggedInException e1){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
    		   	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e2) {
    		   		logger.warning(e2.getMessage());
    		   		returnValue = "System faliure";
    		   		return false;
    		   	}
    }

    		public boolean addTopic(String newTopic,String firstPostTitle,String firstPostContent) {
    			try {
	        		 forum.createNewTopicInForum(user, password, forumId, newTopic, firstPostTitle, firstPostContent);
	        		 LinkedList<TopicDataInt> topics = forum.getForumTopicList(user, password, forumId);
	        		 Iterator<TopicDataInt> topicIter = topics.iterator();
	        		 TopicDataInt _topic;
	        		 while (topicIter.hasNext()){
	        			_topic = topicIter.next();
	        			if(_topic.getTitle().equals(newTopic))
	        			topicId = _topic.getId();
	        		   	break;
	        		}
//	        		showTopics();
	        		return true;
	        	} catch (ForumNotFoundException e){
	        		returnValue = "You must choose a forum first";
	        		return false;
	        	} catch(NotLoggedInException e1){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
	        	} catch (NoPermissionException e2){
	        		returnValue = "You must be an administrator to add a new toppic";
	        		return false;
    		   	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e3) {
    		   		logger.warning(e3.getMessage());
    		   		returnValue = "System faliure";
    		   		return false;
	        	}
    		}
    		
                public boolean showTopics() {
                try {
                                LinkedList<TopicDataInt> _topics = forum.getForumTopicList(user, password,forumId);
                                topics = listToVector(_topics);
                                return true;
                        }  catch(ElementNotFoundException e){
                                returnValue = "You must choose a forum first";
                                return false;
                        } catch(NotLoggedInException e1){
                                logged = false;
                                returnValue = "Time out, you must login again";
                                return false;
                        } catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e2) {
                                logger.warning(e2.getMessage());
                                returnValue = "System faliure";
                                return false;
                        }
                }

    		public boolean creatForum(String forumName) {
    			try {
    				forum.createForum(user, password, forumName);
//    				showForums();
    				return true;
    			} catch(NotLoggedInException e){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
	        	} catch (NoPermissionException e1){
	        		returnValue = "You must be an administrator to add a new toppic";
	        		return false;
    		   	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e2) {
    		   		logger.warning(e2.getMessage());
    		   		returnValue = "System faliure";
    		   		return false;
	        	}
    }

    		public boolean showForums() {
    			try {
				  		LinkedList<ForumDataInt> _forums = forum.getForumList(user, password);
//	    		   		if(forums.size() == 0){
//	    		   			System.out.println("No forums avaliable");
//	    		   			return forums;
//	    		   		}
	    		   		forums = listToVector(_forums);
				  		return true;
	    		   	} catch(NotLoggedInException e1){
	    		   		logged = false;
	    		   		returnValue = "Time out, you must login again";
	    		   		return false;
	    		   	} catch (SQLException e7) {
                                        returnValue = getSQLerror();
                                        logger.warning(e7.getMessage());
                                        return false;
                                } catch (Exception e2) {
	    		   		logger.warning(e2.getMessage());
	    		   		e2.printStackTrace();
	    		   		returnValue = "System failure";
	    		   		return false;
	    		   	}
    }

    		public boolean removeFriend(String friendUserName) {
    			try {
	        		   	forum.removeFriend(user, password, friendUserName);
	        		   	return true;
    			}catch(FriendNotFoundException e){
    				returnValue = "There is no such user with the user name: "+friendUserName;
    				return false;
    			} catch(NotLoggedInException e1){
	    			logged = false;
	    			returnValue = "Time out, you must login again";
	    			return false;
    			} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e2) {
    				logger.warning(e2.getMessage());
	    		   	returnValue = "System faliure";
	    		   	return false;
    			}
    		}

    		public boolean showMyFriends() {
    			try{
    				LinkedList<MemberDataInt> _friends = forum.getUserFriends(user, password);
    				friends = listToVector(_friends);
    				return true;
    			} catch(NotLoggedInException e4){
    		   		logged = false;
    		   		returnValue = "Time out, you must login again";
    		   		return false;
	        	} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e5) {
    		   		logger.warning(e5.getMessage());
    		   		returnValue = "System faliure";
    		   		return false;
	        	}
    }

    		public boolean addFriend(String friendUserName) {
    			try {
    				LinkedList<MemberDataInt> usrFriends = forum.getUserFriends(user, password);
    				for(MemberDataInt frnd:usrFriends)
    					if(frnd.getUserName().equals(friendUserName)){
    						returnValue = friendUserName + " is allready in your friends list";
        					return false;
    					}
    					else continue;
    					forum.addFriend(user, password, friendUserName);
        				return true;
    			} catch(FriendNotFoundException e){
    				returnValue = "There is no such user with the user name: "+friendUserName;
    				return false;
    			} catch(NotLoggedInException e1){
	    			logged = false;
	    			returnValue = "Time out, you must login again";
	    			return false;
    			} catch (SQLException e7) {
                                returnValue = getSQLerror();
                                logger.warning(e7.getMessage());
                                return false;
                        } catch (Exception e2) {
    				logger.warning(e2.getMessage());
	    		   	returnValue = "System faliure";
	    		   	return false;
    			}
    		}

                public String getUsername(){
                    return this.user;
                }
    		
                public boolean isAdmin(){
                    return admin;
                }

    		private <E> Vector<E> listToVector(LinkedList<E> lst){
    			Vector<E> ans = new Vector<E>();
    			Iterator<E> iter = lst.iterator();
    			while(iter.hasNext())
    				ans.add(iter.next());
    			return ans;
    		}

                private String getSQLerror(){
                    return "Error: The server's SQL DataBaseis temporarily down ! Please try later.";
                }
                
}

 
